/*
MIT License

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo
*/

#ifndef simodo_module_HardModuleFactory
#define simodo_module_HardModuleFactory

/*! \file Host_interface.h
    \brief Интерфейс управляющего кода модуля
*/

#include "simodo/variable/Module_interface.h" 

#include <memory>
#include <functional>
#include <vector>

namespace simodo::interpret
{
    class Interpret_interface;
}

namespace simodo::module
{
    typedef std::shared_ptr<variable::Module_interface> (ExtModuleFactory_t)(interpret::Interpret_interface *);

    /**
     * \brief Реализация загружаемого из dll модуля.
     * 
     * \note Особенность загружаемого из библиотеки модуля в том, что нужно для 
     * каждого вызова instantiate создавать уникальный модуль. Иначе изменение состояния 
     * для одного повлечёт синхронные изменения состояния других. Чтобы избежать 
     * такого поведения понадобилось сохранять каждый созданный модуль в контейнере.
     * 
     * \todo Применённый подход мешает динамическому освобождению модулей, что может приводить
     * к неэффективному использованию памяти.
    */
    class HardModule : public variable::Module_interface
    {
        std::function<ExtModuleFactory_t>                        _creator;
        interpret::Interpret_interface *                         _interpret;
        std::vector<std::shared_ptr<variable::Module_interface>> _modules;

    public:
        HardModule() = delete;
        HardModule(std::function<ExtModuleFactory_t> creator, interpret::Interpret_interface * interpret=nullptr); 

        virtual version_t version() const override;
        virtual variable::Object instantiate(std::shared_ptr<Module_interface> module_object) override;
    };

}

#endif // simodo_module_HardModule_abstract
